import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'
import type { App, Plugin, Component } from 'vue'

function isObject(val: any): val is Record<string, any> {
  return val !== null && typeof val === 'object'
}

/**
 * 用于将对象转换为URL的param参数
 * @param baseUrl 基础url
 * @param obj 对象
 * @returns
 */
export function setObjToUrlParams(baseUrl: string, obj: any): string {
  // 定义一个空字符串，用于存储参数
  let parameters = ''
  // 遍历对象中的所有属性
  for (const key in obj) {
    // 将属性名和属性值拼接成参数字符串，并使用encodeURIComponent进行编码
    parameters += key + '=' + encodeURIComponent(obj[key]) + '&'
  }
  // 去掉最后一个&符号
  parameters = parameters.replace(/&$/, '')
  // 如果baseUrl以?结尾，则直接拼接参数，否则在baseUrl后面加上?再拼接参数
  return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters
}

/**
 * 导出一个函数，用于深度合并两个对象
 * @param src 源对象
 * @param target
 * @returns
 */
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
  // 定义一个变量，用于存储目标对象的键名
  let key: string
  // 遍历目标对象的键名
  for (key in target) {
    // 如果源对象中对应的键名是对象，则递归调用deepMerge函数进行深度合并
    src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key])
  }
  // 返回合并后的源对象
  return src
}

/**
 * 用于打开一个窗口层
 * @param url
 * @param opt
 */
export function openWindowLayer(url: string, opt?: { width?: number; height?: number }) {
  // 将window对象转换为any类型
  const win = window as any
  // 获取窗口宽度，如果opt中指定了宽度，则使用指定的宽度，否则使用窗口的宽度
  let layerWidth = opt?.width || win.$(win).width()
  // 如果窗口宽度小于800，则减去30，否则减去200
  if (layerWidth < 800) {
    layerWidth -= 15 * 2
  } else {
    layerWidth -= 100 * 2
  }
  // 获取窗口高度，如果opt中指定了高度，则使用指定的高度，否则使用窗口的高度
  let layerHeight = opt?.height || win.$(win).height()
  // 如果窗口高度小于500，则减去30，否则减去50
  if (layerHeight < 500) {
    layerHeight -= 15 * 2
  } else {
    layerHeight -= 25 * 2
  }
  // 使用layer.open方法打开窗口层
  win.layer.open({
    type: 2,
    maxmin: true,
    shadeClose: true, // 点击背景关闭
    title: false,
    area: [layerWidth + 'px', layerHeight + 'px'],
    method: 'get',
    content: url
  })
}

/**
 * 用于获取原始路由
 * @param route 路由
 * @returns
 */
export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized {
  // 如果没有传入路由，则直接返回路由
  if (!route) return route
  // 将路由中的matched属性和其它属性分开
  const { matched, ...rest } = route
  // 返回一个新的路由对象，其中matched属性为原始路由中的matched属性，其它属性为原始路由中的其它属性
  return {
    ...rest,
    matched: (matched
      ? matched.map((item) => ({
          meta: item.meta,
          name: item.name,
          path: item.path
        }))
      : undefined) as RouteRecordNormalized[]
  }
}

/**
 * 用于给组件添加install方法
 * @param component 组件
 * @param alias 别名
 * @returns
 */
export const withInstall = <T extends Component>(component: T, alias?: string) => {
  // 将组件转换为任意类型
  const comp = component as any
  // 给组件添加install方法
  comp.install = (app: App) => {
    // 将组件注册到app中
    app.component(comp.name || comp.displayName, component)
    // 如果有别名，则将组件添加到app的全局属性中
    if (alias) {
      app.config.globalProperties[alias] = component
    }
  }
  // 返回组件，并添加Plugin和any类型
  return component as T & Plugin & any
}
